class ShimsController < ApplicationController
  before_filter :authorize, :except => [:index, :show, :download, :belonging_to, :with_annotation, :with_type] # overrides :authorize from application_controller
  before_filter :no_user, :only => [:annotated_by, :belonging_to]
  before_filter :no_shim, :only => [:show, :edit, :update, :destroy, :download]
  before_filter :no_annotation_value, :only => :with_annotation
  
  
  
  # shims with a given type
  def with_type
    @shims = Shim.find(:all, :conditions => {:shim_type => params[
        :shim_type]}).paginate :page => params[:page], :per_page => 10
    @message = "No shims could be found with type \'#{params[:shim_type]}\'." if @shims.empty?
  end
  
  # invoked when you click on an annotation
  def with_annotation 
    @annotations = Annotation.with_attribute_name(params[:attribute_name]).find(
        :all, :conditions => {:value => params[:value]})
    get_requested_shims
  end
  
  # shims annotated by a user
  def annotated_by
    @annotations = Annotation.find(:all, :conditions => {:source_type => "User",
        :source_id => params[:user_id]})
    get_requested_shims
  end
  
  # shims belonging to a user
  def belonging_to
    @shims = Shim.find(:all, :conditions => {:user_id => params[:user_id]
        }).paginate :page => params[:page], :per_page => 10
  end
  
  # GET /shims
  # GET /shims.xml
  def index
    @shims = Shim.all.paginate :page => params[:page], :per_page => 10, 
        :order => 'created_at DESC'
    
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @shims }
    end
  end
  
  # GET /shims/1
  # GET /shims/1.xml
  def show
    @shim = Shim.find(params[:id])
    @shim_service = Service.find_by_id(@shim.service_id) if @shim.is_service?
    @shim_inputs = ShimInput.find(:all, :conditions => {:shim_id => params[:id]})
    @shim_outputs = ShimOutput.find(:all, :conditions => {:shim_id => params[:id]})
    
    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :layout => false }
    end
  end
  
  # GET /shims/new
  # GET /shims/new.xml
  def new
    @shim = Shim.new
    @type = params[:type]
    
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @shim }
    end
  end
  
  # GET /shims/1/edit
  def edit
    @shim = Shim.find(params[:id])
  end
  
  # POST /shims
  # POST /shims.xml
  def create
    @shim = Shim.new(params[:shim])
    @type = params[:type]
    
    @shim.user_id = current_user.id
    content_errors = Array.new
    if @type == 'file'
      if params[:shim_blob_data].blank?
        content_errors << "Please specify a file"
      else  
        shim_blob = ShimBlob.new({:data => params[:shim_blob_data].read})
        shim_blob.save
        shim_blob.errors.each_full {|msg| content_errors << msg}       
        @shim.shim_blob_id = shim_blob.id
        @shim.content_type = params[:shim_blob_data].content_type.chomp
        @shim.filename = params[:shim_blob_data].original_filename
      end      
    end
    if @type == 'service'
      shim_service = Service.new(params[:service])
      shim_service.save
      shim_service.errors.each_full {|msg| content_errors << msg}
      @shim.service_id = shim_service.id
    end
    respond_to do |format|
      if content_errors.empty? && @shim.save
        @shim.create_annotations({"description" => [params[:description]]}, current_user)
        format.html { redirect_to(@shim) }
        format.xml  { render :xml => @shim, :status => :created, :location => @shim }
      else
        content_errors.each {|err| @shim.errors.add_to_base(err)}
        format.html { render :action => "new" }
        format.xml  { render :xml => @shim.errors, :status => :unprocessable_entity }
      end
    end
  end
  
  # PUT /shims/1
  # PUT /shims/1.xml
  def update
    @shim = Shim.find(params[:id])
    unless params[:shim_blob_data].blank?
      @shim_blob = ShimBlob.new({:data => params[:shim_blob_data].read})
      @shim_blob.save        
      @shim.shim_blob_id = @shim_blob.id
      @shim.content_type = params[:shim_blob_data].content_type.chomp
      @shim.filename = params[:shim_blob_data].original_filename
    end
    
    if @shim.is_service?
      service = Service.find(@shim.service_id)
      service.update_attributes(params[:service])
    end
    
    respond_to do |format|
      if @shim.update_attributes(params[:shim])
        format.html { redirect_to(@shim) }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @shim.errors, :status => :unprocessable_entity }
      end
    end
  end
  
  # DELETE /shims/1
  # DELETE /shims/1.xml
  def destroy
    shim = Shim.find(params[:id])
    if shim.service_id
      Service.destroy(shim.service_id)
      ServiceLink.destroy_all("service_id = #{shim.service_id}")
    end
    
    ShimInput.find(:all, :conditions => {:shim_id => params[:id]}).each do |x|
      Annotation.destroy_all("annotatable_type='ShimInput' AND annotatable_id=#{x.id}")
    end
    ShimInput.destroy_all("shim_id = #{params[:id]}")
    
    ShimOutput.find(:all, :conditions => {:shim_id => params[:id]}).each do |x|
      Annotation.destroy_all("annotatable_type='ShimOutput' AND annotatable_id=#{x.id}")
    end
    ShimOutput.destroy_all("shim_id = #{params[:id]}")
    
    Annotation.destroy_all("annotatable_type='Shim' AND annotatable_id=#{params[:id]}")
    Shim.destroy(params[:id])
    
    respond_to do |format|
      format.html { redirect_to :back }
      format.xml  { head :ok }
    end
  end
  
  def download
    @shim = Shim.find(params[:id])
    send_data @shim.shim_blob.data, :filename => @shim.filename
  end 
  
  
  
  protected
  
  def authorize
    user = User.find_by_id(session[:user_id])
    unless user # NOT LOGGED IN
      session[:original_uri] = request.request_uri
      flash[:notice] = "Please log in" 
      redirect_to :controller => "home", :action => "login"
    end
  end
  
  
  
  private
  
  def no_user
    begin
      User.find(params[:user_id])
    rescue
      flash[:notice] = "No user could be found with ID #{params[:user_id]}"
      redirect_to :controller => "shims"
    end
  end
  
  def no_shim
    begin
      Shim.find(params[:id])
    rescue
      flash[:notice] = "No shims could be found with ID #{params[:id]}."
      redirect_to :controller => "shims"
    end
  end
  
  def no_annotation_value
    if Annotation.find(:all, :conditions => {:value => params[:value]}).empty? or 
      AnnotationAttribute.find(:all, :conditions => {
        :name => params[:attribute_name]}).empty?
      if params[:attribute_name] =~ /category/i
        @message = "No shims could be found belonging to category \'#{Category.find(params[:value]).name}\'."
      else
        @message = "No shims could be found with attribute \'#{params[:value]}\'."
      end
    end
  end
  
  def get_requested_shims
    @shims = []
    ids = []
    @annotations.each do |x|
      if x.annotatable_type=="Shim"
        begin
          @shims << Shim.find(x.annotatable_id)
          ids << x.annotatable_id
        rescue
          x.destroy
        end
      end
      
      if x.annotatable_type=="ShimInput"
        temp = ShimInput.find(x.annotatable_id)
        @shims << temp.shim
        ids << temp.shim.id
      end
      
      if x.annotatable_type=="ShimOutput"
        temp = ShimOutput.find(x.annotatable_id)
        @shims << temp.shim
        ids << temp.shim.id
      end      
    end
    @shims.uniq!
    ids.uniq!
    @shims = Shim.paginate :conditions => {:id => ids}, :page => params[:page], :per_page => 10
  end
end
